package com.google.code.bigyang.filter.impl;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.google.code.bigyang.base.Session;
import com.google.code.bigyang.filter.Filter;
import com.google.code.bigyang.filter.FilterChain;
import com.google.code.bigyang.filter.FilterEntry;
import com.google.code.bigyang.filter.NextFilter;
import com.google.code.bigyang.nio.NioSession;

public class DefaultFilterChain implements FilterChain {

	private final NioSession session;
	
	private final FilterEntryImpl head;
	
	private final FilterEntryImpl tail;
	
	private Map<String,FilterEntry> name4Entrys = new ConcurrentHashMap<String, FilterEntry>();
	
	public DefaultFilterChain(NioSession session) {
		this.session = session;
		head = new FilterEntryImpl(null, null, "head", new HeadFilter());
		tail = new FilterEntryImpl(null, null, "tail", new TailFilter());
		head.next = tail;
		tail.pre = head;

	}
	
	public void fireMessageReceived(Object message) {
		FilterEntry entry = this.head;
		callMessageReceived(entry,session,message);
	}

	public void fireMessageSent(Object message) {
		FilterEntry entry = this.head;
		callMessageSent(entry,session,message);
	}
	
	
	public Filter getFilterEntry(Filter filter) {
		FilterEntryImpl entry = head.next;
		while( entry != tail ) {
			if( entry.getFilter() == filter ) {
				return filter;
			}
			entry = entry.next;
		}
		return null;
	}
	
	
	
	//FilterEntryImpl invoke method
	
	public void callMessageSent(FilterEntry entry,NioSession session,Object message) {
		Filter filter = entry.getFilter();
		NextFilter next = entry.getNextFilter();
		try {
			filter.messageSent(next, session, message);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void callMessageReceived(FilterEntry entry,NioSession session,Object message) {
		Filter filter = entry.getFilter();
		NextFilter next = entry.getNextFilter();
		try {
			filter.messageReceived(next, session, message);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	@SuppressWarnings("unused")
	private class FilterEntryImpl implements FilterEntry {

		private FilterEntryImpl pre;
		private FilterEntryImpl next;
		private final String name;
		private final Filter filter;
		private final NextFilter nextFilter;
		
		public FilterEntryImpl(FilterEntryImpl pre,FilterEntryImpl next,String name,Filter filter) {
			this.pre = pre;
			this.next = next;
			this.name = name;
			this.filter = filter;
			this.nextFilter = new NextFilter() {
				
				public void messageSent(Session session, Object message) {
					FilterEntry entry = FilterEntryImpl.this.next;
					callMessageSent(entry,(NioSession)session,message);
				}
				
				public void messageReceived(Session session, Object message) {
					FilterEntry entry = FilterEntryImpl.this.next;
					callMessageReceived(entry,(NioSession)session,message);
				}
			};
		}
		
		public String getName() {
			return name;
		}

		public Filter getFilter() {
			return filter;
		}

		public NextFilter getNextFilter() {
			return nextFilter;
		}

		public void addFirst(String name, Filter filter) {
			
		}

		public void addLast(String name, Filter filter) {
			
		}

		public void replace(String name, Filter newFilter) {
			
		}

		public void remove(String name, Filter filter) {
			
		}
		
	}	
	
	
	
	private void checkName(String name) {
		if( name4Entrys.containsKey(name) ) {
			throw new IllegalArgumentException(name + " is exist!");
		}
	}
	
	public synchronized void addFirst(String name,Filter filter) {
		checkName(name);
		register(head,name,filter);
	}
	
	public synchronized void addLast(String name,Filter filter) {
		checkName(name);
		register(tail,name,filter);
	}
	
	public void register(FilterEntryImpl pre,String name,Filter filter) {
		FilterEntryImpl entry = new FilterEntryImpl(pre, pre.next, name, filter);
		pre.next.pre = entry;
		pre.next = entry;
		name4Entrys.put(name, entry);
	}	
	
	

}
